package com.haizhi.crm.sys.configure.service.impl;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.haizhi.crm.common.constant.CrmConstant;
import com.haizhi.crm.common.model.Response;
import com.haizhi.crm.common.util.CommonUtils;
import com.haizhi.crm.sys.configure.dao.ModuleDao;
import com.haizhi.crm.sys.configure.dao.ModuleSettingDao;
import com.haizhi.crm.sys.configure.dao.UserModuleDao;
import com.haizhi.crm.sys.configure.dao.UserModuleSettingDao;
import com.haizhi.crm.sys.configure.model.*;
import com.haizhi.crm.sys.configure.service.UserModuleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by caochao on 2018/06/03.
 */
@Service
public class UserModuleServiceImpl implements UserModuleService {

    @Resource
    private ModuleDao moduleDao;
    @Resource
    private ModuleSettingDao moduleSettingDao;
    @Resource
    private UserModuleDao userModuleDao;
    @Resource
    private UserModuleSettingDao userModuleSettingDao;

    @Override
    public Response list() {
        List<Long> moduleIds = userModuleDao.findModuleIdsBy(CommonUtils.getUserID());

        List<ModuleVo> moduleVos = moduleDao.findAll().stream()
                .map(p -> ModuleVo.fromDo(p))
                .collect(Collectors.toList());

        moduleVos.forEach(p -> {
            if (moduleIds.contains(p.getModuleId())) {
                p.setChecked(true);
            } else {
                p.setChecked(false);
            }
        });
        return Response.success(moduleVos);
    }


    @Override
    @Transactional
    public Response saveUserModule(UserModuleQo userModuleQo) {
        Set<Long> addModuleIds = userModuleQo.getAddModuleIds();
        Set<Long> cancelModuleIds = userModuleQo.getCancelModuleIds();
        Long userId = CommonUtils.getUserID();
        save(addModuleIds, userId);
        cancel(cancelModuleIds, userId);
        return Response.success();
    }

    private void cancel(Set<Long> moduleIds, Long userId) {
        for (Long moduleId : moduleIds) {
            List<UserModuleDo> userModuleDoList = userModuleDao.findByUserIdAndModuleId(userId, moduleId);
            for (UserModuleDo userModuleDo : userModuleDoList) {
                userModuleSettingDao.deleteByUserModuleId(userModuleDo.getId());
            }
            userModuleDao.deleteBy(userId, moduleId);
        }
    }

    private void save(Set<Long> moduleIds, Long userId) {
        for (Long moduleId : moduleIds) {
            List<UserModuleDo> userModuleDoList = userModuleDao.findByUserIdAndModuleId(userId, moduleId);
            if (CollectionUtils.isEmpty(userModuleDoList)) {
                UserModuleDo userModuleDo = new UserModuleDo();
                userModuleDo.setUserId(userId);
                userModuleDo.setModuleId(moduleId);
                userModuleDo.setEnabledFlag(CrmConstant.ENABLE_FLAG);
                userModuleDo.setUpdatedDt(new Date());
                userModuleDo.setCreatedDt(new Date());
                userModuleDao.save(userModuleDo);

                //设置默认模块配置
                List<ModuleSettingDo> moduleSettingDos = moduleSettingDao.findByModuleId(moduleId);
                if (CollectionUtils.isEmpty(moduleSettingDos)) {
                    continue;
                }
                saveUserModuleSetting(userModuleDo, moduleSettingDos);
            }
        }
    }

    private void saveUserModuleSetting(UserModuleDo userModuleDo, List<ModuleSettingDo> moduleSettingDos) {
        List<UserModuleSettingDo> userModuleSettingDos = new ArrayList<>();
        for (ModuleSettingDo moduleSettingDo : moduleSettingDos) {
            if (Boolean.valueOf(moduleSettingDo.getDefaultChecked())) {
                buildUserModuleSetting(userModuleDo.getId(), moduleSettingDo.getId(), "true", userModuleSettingDos);
            } else {
                if ("page_size".equals(moduleSettingDo.getCategory())) {
                    buildUserModuleSetting(userModuleDo.getId(), moduleSettingDo.getId(), "5", userModuleSettingDos);
                } else {
                    buildUserModuleSetting(userModuleDo.getId(), moduleSettingDo.getId(), moduleSettingDo.getShowName(), userModuleSettingDos);
                }
            }
        }
        userModuleSettingDao.save(userModuleSettingDos);
    }

    private void buildUserModuleSetting(Long userModuleId, Long settingId, String settingValue, List<UserModuleSettingDo> userModuleSettingDos) {
        UserModuleSettingDo userModuleSettingDo = new UserModuleSettingDo();
        userModuleSettingDo.setUserModuleId(userModuleId);
        userModuleSettingDo.setSettingId(settingId);
        userModuleSettingDo.setSettingValue(settingValue);
        userModuleSettingDo.setEnabledFlag(CrmConstant.ENABLE_FLAG);
        userModuleSettingDo.setUpdatedDt(new Date());
        userModuleSettingDo.setCreatedDt(new Date());
        userModuleSettingDos.add(userModuleSettingDo);
    }

    @Override
    public Response findModuleSettings(Long moduleId) {
        List<ModuleSettingDo> moduleSettingDos = moduleSettingDao.findByModuleId(moduleId);
        Map<String, List<ModuleSettingDo>> resultMap = new HashMap<>();
        for (ModuleSettingDo moduleSettingDo : moduleSettingDos) {
            String category = moduleSettingDo.getCategory();
            if (resultMap.containsKey(category)) {
                resultMap.get(category).add(moduleSettingDo);
            } else {
                List<ModuleSettingDo> moduleSettingDos1 = new ArrayList<>();
                moduleSettingDos1.add(moduleSettingDo);
                resultMap.put(category, moduleSettingDos1);
            }
        }
        return Response.success(resultMap);
    }

    @Transactional
    @Override
    public Response saveUserModuleSettings(UserModuleSettingQo userModuleSettingQo) {
        Long userModuleId = userModuleSettingQo.getUserModuleId();
        userModuleSettingDao.deleteByUserModuleId(userModuleId);

        List<UserModuleSettingQo.Setting> settings = userModuleSettingQo.getSettings();
        List<UserModuleSettingDo> userModuleSettingDos = new ArrayList<>();
        for (UserModuleSettingQo.Setting setting : settings) {
            buildUserModuleSetting(userModuleId, setting.getSettingId(), setting.getSettingValue(), userModuleSettingDos);
        }
        userModuleSettingDao.save(userModuleSettingDos);
        return Response.success();
    }

    @Override
    public Response findUserModuleSettings(Long moduleId) {
        UserModuleDo userModuleDo = userModuleDao.findByUserIdAndModuleId(CommonUtils.getUserID(), moduleId).get(0);
        List<UserModuleSettingDo> userModuleSettingDos = userModuleSettingDao.findByUserModuleId(userModuleDo.getId());
        Map<String, Object> map = new HashMap<>();
        map.put("moduleId", moduleId);
        map.put("userModuleId", userModuleDo.getId());
        Map<String, List<Map<String, Object>>> setCategoryItems = new HashMap<>();
        for (UserModuleSettingDo userModuleSettingDo : userModuleSettingDos) {
            Long settingId = userModuleSettingDo.getSettingId();
            ModuleSettingDo moduleSettingDo = moduleSettingDao.findOne(settingId);
            String category = moduleSettingDo.getCategory();

            Map<String, Object> setting = new HashMap<>();
            setting.put("settingId", settingId);
            setting.put("settingValue", userModuleSettingDo.getSettingValue());
            setting.put("name", moduleSettingDo.getName());
            setting.put("showName", moduleSettingDo.getShowName());

            if (!setCategoryItems.containsKey(category)) {
                setCategoryItems.put(category, new ArrayList<>());
            }
            setCategoryItems.get(category).add(setting);
        }
        map.putAll(setCategoryItems);
        return Response.success(map);
    }

    @Override
    public UserModuleSettingVo findUserModuleSetting(Long userModuleId) {
        UserModuleDo userModuleDo = userModuleDao.findOne(userModuleId);
        List<ModuleSettingVo> moduleSettingVos = moduleSettingDao.findByModuleId(userModuleDo.getModuleId())
                .stream().map(p -> ModuleSettingVo.fromDo(p))
                .collect(Collectors.toList());

        List<UserModuleSettingItemVo> settingItemVos = moduleSettingVos
                .stream()
                .map(one -> {
                    UserModuleSettingItemVo.UserModuleSettingItemVoBuilder builder = UserModuleSettingItemVo.builder().settingItem(one);
                    UserModuleSettingDo moduleSettingDo = userModuleSettingDao.findByUserModuleIdAndSettingId(userModuleDo.getId(), one.getSettingId());
                    if (moduleSettingDo != null) {
                        builder.settingValue(moduleSettingDo.getSettingValue());
                    }
                    return builder.build();
                }).collect(Collectors.toList());

        Multimap<String, UserModuleSettingItemVo> myMultimap = ArrayListMultimap.create();
        settingItemVos.forEach(one -> myMultimap.put(one.getSettingItem().getCategory(), one));

        List<UserModuleSettingCategoryVo> categoryVos = myMultimap.asMap()
                .keySet()
                .stream()
                .map(k -> new UserModuleSettingCategoryVo(k, Lists.newArrayList(myMultimap.get(k))))
                .collect(Collectors.toList());
        return UserModuleSettingVo.builder().userModuleId(userModuleId).categorys(categoryVos).build();
    }
}
